#define PrynInternal
#define PrynImplementation
#include <pryn.h>
#include "strings.h"

#define PrynCheckValue() do { prynAssert (value, NullArgument); state = value->pState; } while (0)

#define PrynValueBody(BODY) PrynBaseBody (self, { state = self->pState; do { BODY } while (0); })
#define PrynValueGetProperty(PropName, PropType, PropInitial, PropValue) PrynBaseGetProperty (, Value, self, PropName, PropType, PropInitial, PropValue)
#define PrynValueSetProperty(PropName, PropType, PropAssign) PrynBaseSetProperty (, Value, self, PropName, PropType, PropAssign)

PrynExport (PrynResult, prynValueState, (PrynValue *value, PrynState **output))
{
	if (output) *output = 0;
	if (!value) return PrynResultNullArgument;
	if (output) *output = value->pState;
	return PrynResultSuccess;
}

PrynValueGetProperty (Type, PrynType *, 0, { if (output) *output = self->pType; })
PrynValueGetProperty (Pointer, void *, 0, { if (output) *output = self->pPointer; })

PrynExport (PrynResult, prynValueDestroy, (PrynValue *value))
{
	PrynStartFunction ();
	PrynCheckValue ();

	prynValueDisassociate (value);
	prynFree (state, value);

	PrynEndFunction ();
}

PrynExport (PrynResult, prynValueDisassociate, (PrynValue *value))
{
	PrynStartFunction ();
	PrynCheckValue ();

	if (value->pType)
	{
		result = value->pType->pDestroyFunction (value, value->pType->pDestroyFunctionData);
		prynDListRemoveP (value->pType->pValues, value);
	}

	value->pType = 0;
	value->pPointer = 0;

	PrynEndFunction ();
}

PrynExport (PrynResult, prynValueAllocate, (PrynValue **output, PrynType *type, size_t length, void *initial))
{
	PrynStartFunction ();
	PrynValue *value = 0;

	if (output) *output = 0;
	prynAssert (output && type, NullArgument);
	state = type->pState;

	prynCall (prynAllocateCleared (state, sizeof (PrynValue) + length, &value));

	value->pState = state;
	value->pType = type;
	value->pPointer = (void *) (value + 1);
	if (initial) prynCopyMemory (value->pPointer, initial, length);
	prynDListAppendP (type->pValues, value);

	*output = value;

	PrynEndFunction ();
}

PrynExport (PrynResult, prynValueCreateFromId, (PrynValue **output, PrynState *state, const PrynString *id, void *initial))
{
	PrynStartFunctionHasState ();
	PrynType *type;

	if (output) *output = 0;
	prynAssert (output && state && id, NullArgument);
	for (type = 0; !prynStateIterateTypes (state, &type); )
		if (!prynStringEqual (&type->pId, id))
			prynReturnCall (prynValueCreate (output, type, initial));

	prynReturnFailure (IdNotFound);
	PrynEndFunction ();
}

PrynExport (PrynResult, prynValueCreate, (PrynValue **output, PrynType *type, void *initial))
{
	PrynStartFunction ();

	if (output) *output = 0;
	prynAssert (output && type, NullArgument);
	state = type->pState;

	prynCall (prynLibraryLoad (type->pLibrary));
	prynAssert (type->pCreateFunction, Failure);
	prynReturnCall ((*type->pCreateFunction) (output, type, initial, type->pCreateFunctionData));
	PrynEndFunction ();
}

PrynExport (PrynResult, prynValueConnectionImage, (PrynValue *value, int width, int height, PrynColor *image, PrynColor *fallback))
{
	if (value && value->pType)
		return value->pType->pConnectionImageFunction (value, width, height, image, fallback, value->pType->pConnectionImageFunctionData);
	else
	{
		prynTypeClearConnectionImage (width, height, image, fallback, prynColorRed);
		return PrynResultNullArgument;
	}
}

PrynExport (PrynResult, prynValueColors, (PrynValue *value, PrynColor *outer, PrynColor *inner))
{
	if (outer) *outer = prynColorGray (128);
	if (inner) *inner = prynColorGray (230);
	if (!value || !value->pType) return PrynResultNullArgument;
	if (!value->pType->pColorsFunction) return PrynResultDone;
	return value->pType->pColorsFunction (value, outer, inner, value->pType->pColorsFunctionData);
}
